#pragma once

#include <metalc/base/mlayer.h>
#include <metalc/errhdl.h>
#if (WORD_WIDTH == 64)
	#define MAGIC_NUM ((word_t)0xDEADBEEFFEEDDEAD)
#else
	#define MAGIC_NUM ((word_t)0xDEADBEEF)
#endif

#define FREE_STATE (0x5UL) // 0b110

static inline word_t cal_chksum(word_t val, word_t key)
{
	return val ^ key;
}

typedef struct ssnode
{
	// mobj_t _obj;
	struct ssnode *next;
	word_t size;
} ssnode_t;
/* 计算异或编码 */
typedef struct
{
	// 放入延迟释放链表
	ssnode_t *delayed_head;
	ssnode_t *delayed_tail;
	word_t delayed_cnt;
	word_t delayed_size;
	// word_t total_cnt;
} delayed_obj_t;


static inline delayed_obj_t *delayed_init(void *ptr)
{
	delayed_obj_t *ret = (delayed_obj_t *)ptr;
	ret->delayed_head = (ssnode_t *)&ret->delayed_head;
	ret->delayed_tail = (ssnode_t *)&ret->delayed_head;
	ret->delayed_cnt = 0;
	ret->delayed_size = 0;
	return ret;
}

static inline delayed_obj_t *delayed_create(perm_allocf_t *alloc)
{
	void *p = alloc(sizeof(delayed_obj_t));
	if (!p)
		return NULL;
	return delayed_init(p);
}


// CEFF_HANDLER(delayed, MERRH_CEFF_ALL)
OU2INFUN(merr_outf, delayed)

SAI void _delayed_pinit(const mlfunc_t * cont, INFUN(delayed, infun)){
	PARAM_USED(cont, infun);
	INFO("delayed pinit\n");
}
SAI void _delayed_tinit(const mlfunc_t * cont, perm_allocf_t *alloc, INFUN(delayed, infun)){
	PARAM_USED(infun);
	/* INFO("delayed tinit\n"); */
	mtls_t *tls = mtls_get();
	if (!tls->objs[cont->lidx]) tls->objs[cont->lidx] = delayed_create(alloc);
}
SAI void   *_delayed_alloc(mreq_t *req, const mlfunc_t * cont){
	/* 最少需要这么多 */
	// req->size = align_up(req->size, sizeof(ssnode_t));
	if (req->size < sizeof(ssnode_t)) req->size = sizeof(ssnode_t);

	return cont->lalloc(req);
}
SAI bool_t _delayed_free(mreq_t *req, const mlfunc_t * cont, const size_t max_delayed_size, INFUN(delayed, infun)){
	mtls_t *tls = mtls_by_req(req);
	delayed_obj_t *l = (delayed_obj_t *)mtls_lobj(tls, cont->lidx);
	ssnode_t *cur = (ssnode_t *)req->ptr;
	size_t size;
	l->delayed_cnt += 1;
	l->delayed_size += req->size;
	// INFO("delayed f%p, %lu\n", cur, req->size);
	cur->size = cal_chksum(req->size | FREE_STATE, MAGIC_NUM);
	cur->next = (ssnode_t *)&l->delayed_head;

	/* 连接尾部 */
	l->delayed_tail->next = (ssnode_t *)cal_chksum((word_t)cur, ((word_t)&l->delayed_head >> PAGE_SHIFT) ^ MAGIC_NUM);
	l->delayed_tail = cur;

	if (l->delayed_size > max_delayed_size)
	{
		// 出队头部的内存
		cur = l->delayed_head;

		// 头部经过加密需要解密还原
		cur = (ssnode_t *)cal_chksum((word_t)cur, ((word_t)&l->delayed_head >> PAGE_SHIFT) ^ MAGIC_NUM);
		// 检测是否合法
		size = cal_chksum(cur->size, MAGIC_NUM);
		if (!(size & FREE_STATE))
		{
			infun->merr_raise(cur, size, MERR_CORRUPTED_HEAD);
		}
		size = size & (~FREE_STATE);

		// 还原
		l->delayed_head = cur->next;
		l->delayed_cnt -= 1;
		l->delayed_size -= size;

		ASSERT(l->delayed_head);
		// if (UNLIKELY(!l->delayed_head))
		// {
		//	 // 恢复初始状态
		//	 l->delayed_tail = (ssnode_t *)&l->delayed_head;
		// }

		// 填充req 释放
		req->ptr = cur;
		req->size = size;
		req->nr = 1;
		cont->lsizeof(req);
		// INFO("delayed finally f%p, %lu\n", cur, size);
		return cont->lfree(req);
	}

	return TRUE;
}
SAI size_t _delayed_sizeof(mreq_t *req, const mlfunc_t * cont){
	return cont->lsizeof(req);
}

#define DEF_DELAYED_MLAYER(name, delayed_size, perm_alloc, errhdl_name)\
DEF_MLAYER_BASIC(name, -1, 1)\
SAI void name##_pinit(const mlfunc_t * cont){ return _delayed_pinit(cont, OUFUN_OF(errhdl_name)); }\
SAI void name##_tinit(const mlfunc_t * cont){return _delayed_tinit(cont, perm_alloc, OUFUN_OF(errhdl_name)); }\
SAI void *name##_alloc(mreq_t *req, const mlfunc_t * cont){\
	return _delayed_alloc(req, cont);\
}\
SAI bool_t name##_free(mreq_t *req, const mlfunc_t * cont){\
	return _delayed_free(req, cont, delayed_size, OUFUN_OF(errhdl_name));\
}\
SAI size_t name##_sizeof(mreq_t *req, const mlfunc_t * cont){\
	return _delayed_sizeof(req, cont);\
}
